import { VEEdge, VEFace, VEHeader, VEType, VELoop } from "./";

const _u = new BABYLON.Vector3();

export class VEVertex {

  /**
   * 通用状态记录
   */
  public header: VEHeader;

  public index: number;
  private static _counter = -1;

  public position: BABYLON.Vector3 = BABYLON.Vector3.Zero();

  public normal: BABYLON.Vector3 = BABYLON.Vector3.Zero();

  public edge: VEEdge | null = null;

  public loop: VELoop | null = null;



  public constructor() {
    this.header = new VEHeader(VEType.Vertex);
    this.index = ++VEVertex._counter;
  }

  /**
   * vertex序号记录reset
   */
  public static start(): void {
    VEVertex._counter = -1;
  }

  public *freeLoopsOutLoop(start = this.loop) {
    for (const loop of this.loopCW(start)) {
      if (loop.isFree()) {
        yield loop;
      }
    }
    return null;
  }

  public *freeLoopsInLoop(start = this.loop) {
    if (start) {
      for (const loop of this.loopCW(start)) {
        if (loop.pair.isFree()) {
          yield loop.pair;
        }
      }
    }
    return null;
  }


  public *boundaryLoopsOutLoop(start = this.loop) {
    for (const loop of this.loopCW(start)) {
      if (loop.isBoundary()) {
        yield loop;
      }
    }
    return null;
  }


  public *boundaryLoopsInLoop(start = this.loop) {
    for (const loop of this.loopCW(start)) {
      if (loop.pair.isBoundary()) {
        yield loop.pair;
      }
    }
    return null;
  }

  public isFree() {
    if (this.isIsolated()) {
      return true;
    }
    for (const loop of this.loopCW()) {
      if (loop.isFree()) {
        return true;
      }
    }
    return false;
  }

  // 独立的点
  public isIsolated() {
    return this.loop === null;
  }

  public commonFacesWithVertex(other: VEVertex) {
    const faces = new Array<VEFace>();
    for (const loop of this.loopCW()) {
      if (loop.face && loop.face.hasVertex(other)) {
        faces.push(loop.face);
      }
    }
    return faces;
  }


  /**
   * 两点坐标对比，去除冗余点
   * @param position 
   * @param tolerance 
   * @returns 
   */
  public matchesPosition(position: BABYLON.Vector3, tolerance: number = 1e-10): boolean {
    _u.copyFrom(position.subtract(this.position));
    return _u.length() < tolerance;
  }


  public getLoopToVertex(other: VEVertex): VELoop | null {
    for (const loop of this.loopCW()) {
      if (loop.pair.vertex === other) {
        return loop;
      }
    }
    return null;
  }

  public isConnectedToVertex(other: VEVertex) {
    return this.getLoopToVertex(other) !== null;
  }

  public *loopCW(start = this.loop) {
    if (start && start.vertex === this) {
      let curr: VELoop = start;
      do {
        yield curr;
        curr = curr.pair.next;
      } while (curr != start);
    }
    return null;
  }

  public *loopCCW(start = this.loop) {
    if (start && start.vertex === this) {
      let curr: VELoop = start;
      do {
        yield curr;
        curr = curr.prev.pair;
      } while (curr != start);
    }
    return null;
  }


}